package tab

import (
	"fmt"
	"net/http"
	"net/url"

	"code.google.com/awwwe-browser/auralvm/conversation"
	"code.google.com/awwwe-browser/auralvm/param"
	"code.google.com/awwwe-browser/data"
)

// Alternative HTTP handler for sending data back to the view.
var NextContinuer func(http.ResponseWriter, *http.Request, string)
// Final alternative HTTP handler for sending data back to the view.
var StopContinuer func(http.ResponseWriter, *http.Request, string)

// HandlerTabListen handles an http request to speak an existing tab to the user for the view.
func HandlerTabListen(w http.ResponseWriter, r *http.Request) {
	var ok bool
	var values []string
	var tabkey, contentindex, contentcontentindex, contentoptionindex int
	var intro string
	r.ParseForm()
	// tab key
	values, ok = r.Form[param.ParamTabKey]
	if !ok || (ok && len(values) != 1) {
		intro = "I was not able to speak a web page to you because the voice app did not provide the tab key."
		NextContinuer(w, r, intro)
		return
	}
	tabkey, ok = data.StringToInt(values[0])
	if !ok {
		intro = "I was not able to speak a web page to you because the voice app did not provide a valid tab key."
		NextContinuer(w, r, intro)
		return
	}
	// content index
	values, ok = r.Form[param.ParamTabContentIndex]
	if !ok || (ok && len(values) != 1) {
		contentindex = -1
	} else {
		contentindex, ok = data.StringToInt(values[0])
		if !ok {
			contentindex = -1
		}
	}
	// content, content index
	// only used with forms
	// when not a form its not used and defaults to 0
	// each elelement in the form is another conversation.
	// 0 is the form itself (default)
	// 1 is the first element, 2 is the second, etc.
	// the last element is the form submision.
	values, ok = r.Form[param.ParamTabContentContentIndex]
	if ok && len(values) == 1 {
		contentcontentindex, ok = data.StringToInt(values[0])
		if !ok {
			contentcontentindex = 0
		}
	} else {
		// not a form element but a text or nav element
		contentcontentindex = 0
	}
	// content option index
	// when not used defaults to -1.
	// with forms this applies only to the first conversation in the form conversations.
	values, ok = r.Form[param.ParamTabContentOptionIndex]
	if ok && len(values) == 1 {
		contentoptionindex, ok = data.StringToInt(values[0])
		if !ok {
			contentoptionindex = -1
		}
	} else {
		contentoptionindex = -1
	}
	ContinuerTabListen(w, r, data.EmptyString, tabkey, contentindex, contentcontentindex, contentoptionindex, true)
}

// ContinuerTabListen allows the user to listen to a tab for the view.
func ContinuerTabListen(w http.ResponseWriter, r *http.Request, intro string, tabkey, contentindex, contentcontentindex, contentoptionindex int, continueon bool) {
	var ok bool
	var values []string
	var formvalues []string
	var value string
	var err error
	var tab *Tab
	var jsonbb []byte
	var i, length, destindex int
	var formcontroloption *param.FormControlOption
	var conv, destconv *conversation.Conversation
	// get the url
	// find the tab
	length = BrowserTabs.Len()
	if length == 0 {
		intro = "You do not have any tabs yet."
		if continueon {
			NextContinuer(w, r, intro)
		} else {
			StopContinuer(w, r, intro)
		}
		return
	}
	ok = false
	for i = 0; i < length; i++ {
		tab = BrowserTabs.AtIndex(i)
		if tab.Key == tabkey {
			ok = true
			break
		}
	}
	if !ok {
		intro = "I was not able to speak a web page to you because the voice app did not provide a valid tab key."
		if continueon {
			NextContinuer(w, r, intro)
		} else {
			StopContinuer(w, r, intro)
		}
		return
	}
	// form element values selected or entered by the user.
	values, ok = r.Form[param.ParamValue]
	if !ok {
		formvalues = make([]string, 0, 0)
	} else {
		length = len(values)
		formvalues = make([]string, 0, length)
		for _, value = range values {
			value, err = url.QueryUnescape(value)
			if err == nil {
				formvalues = append(formvalues, value)
			}
		}
	}
	ok = false
	i = 0
	// serialize the conversation
	if contentindex < 0 {
		conv = tab.Opener
        conv.Intro = intro
		conv.InitialIndex = contentoptionindex
		jsonbb, err = conv.Marshal()
	} else if contentindex >= len(tab.Contents) {
		conv = tab.TOC
        conv.Intro = intro
		conv.InitialIndex = contentoptionindex
		jsonbb, err = conv.Marshal()
	} else {
		if len(tab.Contents[contentindex]) == 1 {
			conv = tab.Contents[contentindex][0]
            conv.Intro = intro
			conv.InitialIndex = contentoptionindex
		} else {
			// check the form types only
			if len(formvalues) > 0 {
				destindex = contentoptionindex
				if destindex < 0 {
					destindex = 0
				}
				if destindex < len(tab.Contents[contentindex])-1 {
					destconv = tab.Contents[contentindex][destindex]
					switch destconv.Type {
					case conversation.ConversationTypeFormEnterText:
						// the user send input
						// store it and move on to the next form element
						destconv.TextValue.UserValue = formvalues[0]
					case conversation.ConversationTypeFormSingleSelect:
						// the user send input
						// store it and move on to the next form element
						value = formvalues[0]
						for _, formcontroloption = range destconv.MenuOptions {
							formcontroloption.UserSelected = formcontroloption.Value == value
						}
					case conversation.ConversationTypeFormMultipleSelect:
						// the user send input
						// store it and move on to the next form element
						for _, formcontroloption = range destconv.MenuOptions {
							formcontroloption.UserSelected = false
							for _, value = range formvalues {
								if formcontroloption.Value == value {
									formcontroloption.UserSelected = true
									break
								}
							}
						}
					case conversation.ConversationTypeYesNo:
					}
				}
			}
			conv = tab.Contents[contentindex][contentcontentindex]
			conv.Intro = intro
			if contentcontentindex == 0 {
				// the next conversation is the form contents
				conv.InitialIndex = contentoptionindex
				rebuildFormElementList(tab, contentindex, contentoptionindex)
			}
		}
		jsonbb, err = conv.Marshal()
	}
	if err == nil {
		w.Write(jsonbb)
	} else {
		if continueon {
			NextContinuer(w, r, intro)
		} else {
			StopContinuer(w, r, intro)
		}
	}
}

// HandlerTabOpenNew handles an http request to open a web page in a new tab for the view.
func HandlerTabOpenNew(w http.ResponseWriter, r *http.Request) {
	var urlstr, feeditemkey string
	var values []string
	var err error
	var tab Tab
	var intro string
	var jsonbb []byte
	var ok bool
	var conv *conversation.Conversation
	intro = data.EmptyString
	r.ParseForm()
	// get the url
	values, ok = r.Form[param.ParamTabURL]
	if !ok || (ok && len(values) != 1) {
		intro = "I was not able to add the web page to your tabs because the voice app did not provide the web page you are ell."
		NextContinuer(w, r, intro)
		return
	}
	urlstr, err = url.QueryUnescape(values[0])
	if err != nil {
		intro = "I was not able to add the web page to your tabs because i was not able to un escape the web page you are ell."
		NextContinuer(w, r, intro)
		return
	}
	tab, err = BuildTab(urlstr)
	if err != nil {
		// intro = "I was not able to the add the web page to your tabs because there was an error."
		intro = fmt.Sprintf("I was not able to the add the web page to your tabs because %s", err.Error())
		NextContinuer(w, r, intro)
		return
	}
	if len(tab.Contents) == 0 {
		intro = "I was not able to the add the web page to your tabs because i was not able to find any content in the web page."
		NextContinuer(w, r, intro)
		return
	}
	// get the feed item key
	// if len(feeditemkey) > 0 { update feed item slice }
	values, ok = r.Form[param.ParamFeedItemKey]
	if !ok || (ok && len(values) != 1) {
		feeditemkey = data.EmptyString
	} else {
		feeditemkey = values[0]
	}
	_ = feeditemkey
	// add the tab
	BrowserTabs.Append(&tab)
	// serialize the conversation
	conv = tab.Opener
	conv.InitialIndex = -1
	jsonbb, err = conv.Marshal()
	if err == nil {
		w.Write(jsonbb)
	} else {
		NextContinuer(w, r, intro)
	}
}

// HandlerTabReplace handles an http request to replace a tab with a new requested web page for the view.
func HandlerTabReplace(w http.ResponseWriter, r *http.Request) {
	var url, feeditemkey string
	var tabkey int
	var values []string
	var err error
	var tab *Tab
    var tabnew Tab
	var intro string
	var jsonbb []byte
	var index, length int
	var ok bool
	var conv *conversation.Conversation
	intro = data.EmptyString
	r.ParseForm()
	// get the url
	values, ok = r.Form[param.ParamTabURL]
	if !ok || (ok && len(values) != 1) {
		intro = "I was not able to add the web page to your tabs because the voice app did not provide the tab you are ell."
		NextContinuer(w, r, intro)
		return
	}
	url = values[0]
	// get the feeditemkey
	// if len(feeditemkey) > 0 { update feed item slice }
	values, ok = r.Form[param.ParamFeedItemKey]
	if !ok || (ok && len(values) != 1) {
		feeditemkey = data.EmptyString
	}
	feeditemkey = values[0]
	_ = feeditemkey
	// get the tab key
	values, ok = r.Form[param.ParamTabKey]
	if !ok || len(values) != 1 {
		intro = "I was not able to add the web page to your tabs because the voice app did not provide the tab index."
		NextContinuer(w, r, intro)
		return
	}
	tabkey, ok = data.StringToInt(values[0])
	if !ok {
		intro = fmt.Sprintf("I was not able to speak a web page to you because the voice app did not provide a valid tab key: %s.", values[0])
		NextContinuer(w, r, intro)
		return
	}
	ok = false
	length = BrowserTabs.Len()
	for index = 0; index < length; index++ {
		tab = BrowserTabs.AtIndex(index)
		if tab.Key == tabkey {
			ok = true
			break
		}
	}
	if !ok {
		intro = fmt.Sprintf("I was not able to add the web page to your tabs because the voice app did not provide a correct tab key: %d.", tabkey)
		NextContinuer(w, r, intro)
		return
	}
	tabnew, err = BuildTab(url)
	if err != nil {
		intro = fmt.Sprintf("I was not able to add the web page to your tabs because %s", err.Error())
		NextContinuer(w, r, intro)
		return
	}
	// replace the tab
	BrowserTabs.ReplaceAt(index, &tabnew)
	// serialize the conversation
	conv = tabnew.Opener
	conv.InitialIndex = -1
	jsonbb, err = conv.Marshal()
	if err == nil {
		w.Write(jsonbb)
	} else {
		NextContinuer(w, r, intro)
	}
}

// HandlerTabClose handles an http request to remove a tab for the view.
func HandlerTabClose(w http.ResponseWriter, r *http.Request) {
	var values []string
	var tabkey int
	var ok bool
	var intro string
	var tab *Tab
	var i, length int
	r.ParseForm()
	intro = data.EmptyString
	// get the title
	values, ok = r.Form[param.ParamTabKey]
	if !ok || len(values) != 1 {
		intro = "I was not able to close the tab because the voice app did not provide the tab index."
		NextContinuer(w, r, intro)
		return
	}
	tabkey, ok = data.StringToInt(values[0])
	if !ok {
		intro = "I was not able to speak a web page to you because the voice app did not provide a valid tab key."
		NextContinuer(w, r, intro)
		return
	}
	// find the tab
	ok = false
	length = BrowserTabs.Len()
	if length == 0 {
		intro = "All of your tabs are already closed."
		NextContinuer(w, r, intro)
		return
	}
	for i = 0; i < length; i++ {
		tab = BrowserTabs.AtIndex(i)
		if tab.Key == tabkey {
			ok = true
			break
		}
	}
	if !ok {
		intro = "I was not able to close the tab because the voice app did not provide a correct tab key."
		NextContinuer(w, r, intro)
		return
	}
	// remove the tab
	BrowserTabs.Delete(i)
	intro = "The tab was successfully closed."
	NextContinuer(w, r, intro)
}
